package com.neusoft.ch10.collections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

/*
 * 课堂笔记：
 * 一：集合
 * 1 集合
 *   是一类对象实例的组合；一堆对象的组合形式；
 *   集合中一般存储是对象类型；
 *   因为有多态，Object类是所有类的根类，所有各种类型的对象都可以放到一个Object类型的集合中；
 *   Object类型集合可以存放所有的类的实例对象；
 * 2 集合分类
 *   分为2大类：
 *      -Collection接口的子类：
 *          --List接口：
 *          --Set接口
 *      -Map接口的子类：  
 * 3 List集合
 *   list集合元素有下标，可以下标进行存取；
 *   list集合的长度可以动态改变；  
 *   list集合的底层实现有数组和链表两种形式；
 *       数组实现（ArrayList）：具有数组的特性；读取速度快；增删速度慢；
 *       链表实现（LinkedList）：具有链表的特性；读取速度慢，增删速度快；
 *   Vector是ArrayList和LinkedList的线程安全类；
 *       
 *   集合的遍历；
 *   list集合的元素是对象类型；所有list中也可以放list对象；（类似于二维数组）
 *   
 *   集合的特性：
 *       是否重复            是否可以为null            是否有序                             是否排序
 *         T             T                    T                 F
 *   注意：
 *      有序是指存入集合中的元素的顺序和遍历集合的元素的顺序一致，叫做有序；
 *      排序是指存入集合中的元素在遍历集合的元素时会按照某种排序规则进行排序，叫做排序；
 * 4 Set集合
 *   Set也是存储对象的集合；
 *   Set集合因为采用散列储存方式，所有元素没有下标；
 *   Set集合只有存入元素的方法add，没有取出指定元素的方法；
 *   元素只能通过遍历的方式依次取出；
 *   Set集合不允许重复；
 * 4.1 HashSet实现子类
 *   通过hash散列算法，决定每个元素在集合中的存储位置；  
 *   
 *   HashSet集合的特性：
 *       是否重复            是否可以为null            是否有序                             是否排序
 *         F             T                    F                 F
 *   HashSet不允许重复，元素允许为null，不是有序的，不会对元素进行排序；
 * 4.2 LinkedHashSet
 *   底层是链表实现
 *   
 *   LinkedHashSet集合的特性：
 *       是否重复            是否可以为null            是否有序                             是否排序
 *         F             T                    T                 F
 *   LinkedHashSet不允许重复，元素允许为null，是有序的，不会对元素进行排序；
 * 4.3 TreeSet
 *   底层是Tree存储实现的；
 *   TreeSet集合的特性：
 *       是否重复            是否可以为null            是否有序                             是否排序
 *         F             F                    F                 T
 *   TreeSet不允许重复，元素不允许为null，不是有序的，会对元素进行排序；
 *   排序的标准支持：8种基本类型的包装类类型和String类型（字典排序）
 *               自定义类的排序规则需要通过继承Comparable接口或提供比较器进行排序；      
 * 5 map集合
 * 5.1 map集合
 *   map集合中存储的是键值对；
 *   键值对由键和值构成；一个键对应一个值；键和值是对应关系；
 *   键和值的数据类型可以为任意类型，一般，键采用String类型；值采用对象类型；
 *   键值对在map集合中是一个元素，map中的一个元素是键值对。
 *   java用EntrySet类来定义键值对；
 *   map也是采用散列算法进行存储；map的散列算法是对键值对中的键进行散列；
 *   所有使用hash散列算法进行存储的方式，元素都没有下标；
 * 5.2 HashMap
 *   对键值对的键采用散列算法进行存储；(无序)
 *   
 *   迭代器无法直接遍历map集合（map没有继承Iterable接口），
 *   但是可以通过获取keySet或者EntrySet的迭代器进行间接的迭代方式进行迭代；           
 *         
 *   HashMap集合的特性：
 *       是否重复(key)     是否可以为null(key)       是否有序(key)      是否排序(key)
 *         F                    T                    F                 F      
 * 5.3 LinkedHashMap
 *   使用链表实现；（有序）
 *   LinkedHashMap集合的特性：
 *       是否重复(key)     是否可以为null(key)       是否有序(key)      是否排序(key)
 *         F                    T                    T                 F    
 * 5.4 TreeMap
 *    使用树型结果存储（排序）
 *    LinkedHashMap集合的特性：
 *       是否重复(key)     是否可以为null(key)       是否有序(key)      是否排序(key)
 *          F                    F                    F                 T              
 * 6、泛型
 *    泛型一般是指代某一类类型；
 *    泛型一般用在两个方法：
 *       一个是声明定义时（多用于方法、类定义）；---泛化
 *          定义声明时，使用泛型指代某一类类型；
 *       一个是用于应用时（指定具体的类型）； ---具体化
 *          应使用时，一般将泛型具体化为某种具体的类型；
 *          
 *    泛型默认使用的类型是Object类型。  
 *    使用泛型定义方法可以替代重载，减少方法定义的个数；
 *    
 * 7、工具类
 *    Collections是集合的工具类；类似于Arrays是数组的工具类一样；
 *    
 * 8、比较接口和比较器
 *    Collections工具类中的max、min、sort等方法，只能对8种基本类型和String类型进行处理；
 *    无法对自定义类型进行处理；自定义类型需要提供比较器或者实现接口；  
 *    提供一个比较器类实现Comparator接口；
 *    让自定义了实现comparable接口；
 *    
 * 9、总结：
 *   list可以重复；
 *   hash实现不可以重复；
 *   排序就不可能有序，互斥；
 *   linked有序；
 *   tree都是排序；
 *   排序的不能为null,不排序的可以为null;  
 *   
 *   list+map的使用
 *   比较器和比较接口的对自定义类的扩展使用；
 *      
 */
public class TestCh10 {

	public static void main(String[] args) {
		test083();
	}
	
	/**
	 * 实现比较接口对学生集合进行排序
	 */
	private static void test083() {
		// 创建一个list数组
		List<Student2> lst = new ArrayList<>();
		// 存入元素
		lst.add(new Student2("张三", "15001", 80));
		lst.add(new Student2("张四", "15002", 70)); // 基本类型默认转换为包装类类型
		lst.add(new Student2("张五", "15003", 90));
		lst.add(new Student2("张六", "15004", 60));
		System.out.println("list排序之前的内容：");
		printList(lst);
		// 调用工具类进行排序
		Collections.sort(lst);
		

		System.out.println("list排序之后的内容：");
		printList(lst);
	}
	
	/**
	 * 使用匿名内部类比较学生大小
	 */
	private static void test0821() {
		// 创建一个list数组
		List<Student> lst = new ArrayList<>();
		// 存入元素
		lst.add(new Student("张三", "15001", 80));
		lst.add(new Student("张四", "15002", 70)); // 基本类型默认转换为包装类类型
		lst.add(new Student("张五", "15003", 90));
		lst.add(new Student("张六", "15004", 60));
		System.out.println("list排序之前的内容：");
		printList(lst);
		// 调用工具类进行排序
		// StudentComparator stuC = new StudentComparator();
		// Collections.sort(lst,stuC);
		
		Collections.sort(lst, new Comparator<Student>() {
			@Override
			public int compare(Student stu1, Student stu2) {
				// 要求返回三类值：大于0，等于0，小于0
				// 根据业务逻辑，比较标准是按成绩高低排序
				// 比较结果
				int result = 0;
				// stu1成绩>stu2成绩
				if (stu1 != null && stu2 != null) {
					// 大于
					if (stu1.getStuScore() > stu2.getStuScore()) {
						result = 1;
					} else if (stu1.getStuScore() < stu2.getStuScore()) {
						// 小于
						result = -1;
					} else {
						result = 0;
					}
				}
				// 返回值
				return result * -1;
			}
		});

		System.out.println("list排序之后的内容：");
		// 调用打印子方法
		printList(lst);
	}
	/**
	 * 使用比较器对学生集合进行排序
	 */
	private static void test082() {
		// 创建一个list数组
		List<Student> lst = new ArrayList<>();
		// 存入元素
		lst.add(new Student("张三", "15001", 80));
		lst.add(new Student("张四", "15002", 70)); // 基本类型默认转换为包装类类型
		lst.add(new Student("张五", "15003", 90));
		lst.add(new Student("张六", "15004", 60));
		System.out.println("list排序之前的内容：");
		printList(lst);
		// 调用工具类进行排序
		// StudentComparator stuC = new StudentComparator();
		// Collections.sort(lst,stuC);
		
		Collections.sort(lst, new StudentComparator());

		System.out.println("list排序之后的内容：");
		printList(lst);
	}

	private static void test081() {
		// 创建一个list数组
		List<String> lstStr = new ArrayList<>();
		// 存入元素
		lstStr.add("xiaoming");
		lstStr.add("xiaoli"); // 基本类型默认转换为包装类类型
		lstStr.add("xiaozhao2");
		lstStr.add("xiaozhao1");
		System.out.println("list排序之前的内容：");
		printList(lstStr);
		// 调用工具类进行排序
		Collections.sort(lstStr);

		System.out.println("list排序之后的内容：");
		printList(lstStr);
	}

	/**
	 * 打印list内容
	 * 
	 * @param lst
	 *            被打印的list
	 */
	private static void printList(List lst) {
		// 获取集合的迭代器
		Iterator<Object> it = lst.iterator();
		// 使用hasNext判定有没有可以遍历的元素
		while (it.hasNext()) {
			// 取出当前遍历的元素
			Object obj = it.next();
			// 输出当前遍历的元素内容
			System.out.println("  " + obj);
		}

	}

	/**
	 * List集合应用泛型
	 */
	private static void test061() {
		// 面向接口的编程
		// list使用时指明了具体的类型之后，list就只能存放指定的具体类型的数据了
		List<String> lst = new ArrayList<>();// new Vector();//new LinkedList();
		// 存入元素
		lst.add("xiaoming");
		lst.add("xiaoli"); // 基本类型默认转换为包装类类型
		lst.add("xiaozhao");
		lst.add("xiaozhao");
		// lst.add(0); // 不能存放其他类型

		// 插入到制定下标的位置进行存储，插队方式存储
		lst.add(2, "xiaowang");
		// 遍历
		System.out.println("迭代器遍历方式：");
		// 获取集合的迭代器
		Iterator<String> it = lst.iterator();
		// 使用hasNext判定有没有可以遍历的元素
		while (it.hasNext()) {
			// 取出当前遍历的元素
			String obj = it.next();
			// 输出当前遍历的元素内容
			System.out.print("  " + obj);
		}
		// 换行
		System.out.println();

		System.out.println("for循环遍历：");
		for (int i = 0; i < lst.size(); i++) {
			// 取出当前遍历的元素
			String obj = lst.get(i);
			// 输出当前遍历的元素内容
			System.out.print("  " + obj);
		}
		// 换行
		System.out.println();
		System.out.println("增强型的for循环遍历：");
		for (String str : lst) {
			// 输出当前遍历的元素内容
			System.out.print("  " + str);
		}

	}

	/**
	 * map集合泛型应用
	 */
	private static void test062() {
		// 创建map集合对象
		// 面向接口的编程思想
		// 多态
		Map<String, Object> map0 = new TreeMap<String, Object>();// new LinkedHashMap();//new HashMap();

		// 存入元素:使用put方法，以键值对的形式进行存储；
		map0.put("stuName", "zhangsan");
		map0.put("stuName", "lisi"); // 后面会覆盖前面的
		map0.put("stuAge", 20);
		map0.put("stuSex", "男");
		// map0.put(null, "男");
		// 遍历元素
		// 迭代遍历map集合
		System.out.println("使用KeySet集合迭代器遍历map集合:");
		// 获取所有键的Set集合对象
		Set<String> keys = map0.keySet();
		// 获取键的Set集合的迭代器对象
		Iterator<String> it = keys.iterator();
		// 迭代键的名字的集合方式，间接迭代map集合
		while (it.hasNext()) {
			// 取出的是当前键的内容
			String keyName = it.next();
			// 使用map的get方法获取与键对应的值
			Object objVal = map0.get(keyName);
			System.out.println(keyName + "-" + objVal);
		}

		System.out.println("使用EntrySet集合迭代器遍历map集合:");
		// 获取set集合的EntrySet集合对象
		Set<Entry<String, Object>> entrys = map0.entrySet();
		// 获取EntrySet集合对象迭代器
		Iterator<Entry<String, Object>> it1 = entrys.iterator();
		while (it1.hasNext()) {
			// 获取当前的键值对对象
			Entry<String, Object> en = it1.next();
			// 向下溯型
			// Entry en = (Entry) obj;
			// 可以从entry对象中获取键值对中的键和值
			System.out.println(en.getKey() + "-" + en.getValue());
		}
	}

	/**
	 * map集合
	 */
	private static void test02() {
		// 创建map集合对象
		// 面向接口的编程思想
		// 多态
		Map map0 = new TreeMap();// new LinkedHashMap();//new HashMap();

		// 存入元素:使用put方法，以键值对的形式进行存储；
		map0.put("stuName", "zhangsan");
		map0.put("stuName", "lisi"); // 后面会覆盖前面的
		map0.put("stuAge", 20);
		map0.put("stuSex", "男");
		// map0.put(null, "男");
		// 遍历元素
		// 迭代遍历map集合
		System.out.println("使用KeySet集合迭代器遍历map集合:");
		// 获取所有键的Set集合对象
		Set keys = map0.keySet();
		// 获取键的Set集合的迭代器对象
		Iterator it = keys.iterator();
		// 迭代键的名字的集合方式，间接迭代map集合
		while (it.hasNext()) {
			// 取出的是当前键的内容
			Object keyName = it.next();
			// 使用map的get方法获取与键对应的值
			Object objVal = map0.get(keyName);
			System.out.println(keyName + "-" + objVal);
		}

		System.out.println("使用EntrySet集合迭代器遍历map集合:");
		// 获取set集合的EntrySet集合对象
		Set entrys = map0.entrySet();
		// 获取EntrySet集合对象迭代器
		Iterator it1 = entrys.iterator();
		while (it1.hasNext()) {
			// 获取当前的键值对对象
			Object obj = it1.next();
			// 向下溯型
			Entry en = (Entry) obj;
			// 可以从entry对象中获取键值对中的键和值
			System.out.println(en.getKey() + "-" + en.getValue());
		}

		System.out.println("使用EntrySet集合增强型for循环遍历map集合:");
		// 可以再entryset基础之上使用增强型的for遍历
		for (Object obj : map0.entrySet()) {
			// 向下溯型
			Entry en = (Entry) obj;
			// 可以从entry对象中获取键值对中的键和值
			System.out.println(en.getKey() + "-" + en.getValue());
		}

	}

	/**
	 * set集合
	 */
	private static void test01() {
		// 创建集合对象
		// 面向接口的编程思想
		// 多态
		Set set0 = new TreeSet();// new LinkedHashSet();//new HashSet();
		// 存入元素
		// set0.add("xiaozhao");
		set0.add("xiaozhao");
		set0.add("xiaoming");
		set0.add("xiaoli");
		set0.add("xiaoli2");
		// set0.add(null);

		// 遍历云素
		System.out.println("迭代器遍历：");
		// 获取迭代器
		Iterator it = set0.iterator();
		while (it.hasNext()) {
			// 取出当前遍历的元素
			Object obj = it.next();
			// 打印元素内容
			System.out.println(obj);
		}

		// 因为set集合没有下标，不能使用标准的for循环遍历元素

		// 可以使用增强型的for循环遍历
		System.out.println("增强相的for循环遍历：");
		for (Object obj : set0) {
			System.out.println(obj);
		}

		System.out.println();
	}
}
